package sfin.controller;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import sfin.service.CartaoService;
import sfin.service.CategoriaService;
import sfin.service.ContaService;
import sfin.service.LancamentoService;
import sfin.swt.data.DateData;
import sfin.swt.data.LancamentoData;
import sfin.swt.data.LancamentoTableData;
import sfin.swt.data.ResumoData;
import sfin.swt.exception.StatizoException;
import sfin.swt.filter.LancamentoFilter;
import br.com.statizo.financeiro.domain.enums.FormaPagamento;


public class LancamentoController {

	public static final int STATE_NEW = 0;
	public static final int STATE_EDITING = 1;
	public static final int MODE_LIST = 0;
	public static final int MODE_EDIT = 2;	


	public static final int LOAD_PARTIAL_NONE = 0;
	public static final int LOAD_PARTIAL_CATEGORIA = 1;
	public static final int LOAD_PARTIAL_CONTA = 2;
	public static final int LOAD_PARTIAL_FORMA_PGTO = 3;
	public static final int LOAD_PARTIAL_CARTAO = 4;

	private int state;

	private DateData dataPgto = new DateData();
	private DateData dataDiv = new DateData();
	private int categoriaIndex;
	private String descricao;
	private String valor;
	private int contaIndex;
	private int contaTransferenciaIndex;
	private int formaPgtoIndex;
	private int cartaoIndex;

	private String parcelas = "2";
	private boolean pago;
	private boolean parcelado;
	private boolean replicado;

	private LancamentoFilter filter;
	
	private boolean fixPgtDt;

	private ResourceBundle bundle;
	private LancamentoService lancamentoService;
	private ContaService contaService;
	private CartaoService cartaoService;
	private CategoriaService categoriaService;
	
	private boolean loadingPartial = false;
	private int partialLoadFlag = LOAD_PARTIAL_NONE;

	private List<Integer> filteredList = new ArrayList<Integer>();

	private Map<Boolean,int[]> sitColors;
	private int[] selectedIndices;
	private ControllerUtil controllerUtil;
	private boolean vincular;

	public LancamentoController(ResourceBundle bundle, ControllerUtil controllerUtil) {
		this.bundle = bundle;
		this.controllerUtil = controllerUtil;
		filter = new LancamentoFilter();
		
		sitColors = new HashMap<Boolean, int[]>();
		sitColors.put(Boolean.TRUE, new int[]{171,208,188});
		sitColors.put(Boolean.FALSE, new int[]{255,153,153});	

	}

	public void partialLoad(int partialLoadFlag){
		this.loadingPartial = true;
		this.partialLoadFlag = partialLoadFlag;
		loadData( true );
	}

	public DateData getDataPgto() {
		return dataPgto;
	}

	public void setDataPgto(DateData dataPgto) {
		this.dataPgto = dataPgto;
	}

	public DateData getDataDiv() {
		return dataDiv;
	}

	public void setDataDiv(DateData dataDiv) {
		this.dataDiv = dataDiv;
	}

	public int getCategoriaIndex() {
		 return controllerUtil.normalizeOptionToShow(categoriaIndex);
	}

	public void setCategoriaIndex(int categoriaIndex) {
		this.categoriaIndex = controllerUtil.normalizeOptionToSave(categoriaIndex);
	}

	public String getDescricao() {
		return descricao;
	}

	public void setDescricao(String descricao) {
		this.descricao = descricao;
	}

	public String getValor() {
		return valor;
	}

	public void setValor(String valor) {
		this.valor = valor;
	}

	public int getContaIndex() {
		return controllerUtil.normalizeOptionToShow(contaIndex);
	}

	public void setContaIndex(int contaIndex) {
		this.contaIndex = controllerUtil.normalizeOptionToSave(contaIndex);
	}

	public int getContaTransferenciaIndex() {
		return controllerUtil.normalizeOptionToShow(contaTransferenciaIndex);
	}
	
	public void setContaTransferenciaIndex(int contaTransferenciaIndex) {
		this.contaTransferenciaIndex = controllerUtil.normalizeOptionToSave(contaTransferenciaIndex);
	}
	
	public int getFormaPgtoIndex() {
		return controllerUtil.normalizeOptionToShow(formaPgtoIndex);
	}

	public void setFormaPgtoIndex(int formaPgtoIndex) {
		this.formaPgtoIndex = controllerUtil.normalizeOptionToSave(formaPgtoIndex);
	}

	public int getCartaoIndex() {
		return controllerUtil.normalizeOptionToShow(cartaoIndex);
	}

	public void setCartaoIndex(int cartaoIndex) {
		this.cartaoIndex = controllerUtil.normalizeOptionToSave(cartaoIndex);
	}

	public String getParcelas() {
		return parcelas;
	}

	public void setParcelas(String parcelas) {
		this.parcelas = parcelas;
	}

	public boolean isPago() {
		return pago;
	}

	public void setpago(boolean pago) {
		this.pago = pago;
	}

	public int getState() {
		return state;
	}

	public void setParcelado(boolean parcelado) {
		this.parcelado = parcelado;
	}

	public boolean isParcelado(){
		return parcelado;
	}
	
	public void setReplicado(boolean replicado) {
		this.replicado = replicado;
	}
	
	public boolean isReplicado(){
		return replicado;
	}

	public boolean isCategoriaPartialLoading(){
		return this.partialLoadFlag == LOAD_PARTIAL_CATEGORIA;
	}

	public boolean isCartaoLoading(){
		return this.partialLoadFlag == LOAD_PARTIAL_CARTAO;
	}

	public boolean isContaPartialLoading(){
		return this.partialLoadFlag == LOAD_PARTIAL_CONTA;
	}

	public boolean isFormaPgtoPartialLoading(){
		return this.partialLoadFlag == LOAD_PARTIAL_FORMA_PGTO;
	}

	public boolean isLoadingPartial(){
		return this.loadingPartial;
	}

	public void setSelectedIndices(int[] selectedIndices) {
		this.selectedIndices = selectedIndices;
	}

	public void clearSelectionIndices(){
		this.selectedIndices = null;
		loadData();
	}

	public void clearSelection(){
		this.state = STATE_NEW;
		clearSelectionIndices();
	}

	public LancamentoFilter getFilter() {
		return filter;
	}
 
	
	public void gerarSaldo() throws StatizoException{
		lancamentoService.gerarSaldoDoMesAtual();
	}

	public void setCategoriaService(CategoriaService categoriaService) {
		this.categoriaService = categoriaService;
	}

	public void setCartaoService(CartaoService cartaoService) {
		this.cartaoService = cartaoService;
	}

	public void setLancamentoService(LancamentoService lancamentoService) {
		this.lancamentoService = lancamentoService;
	}

	public void setContaService(ContaService contaService) {
		this.contaService = contaService;
	}

	public void setFilter(LancamentoFilter filter) {
		this.filter = filter;
	}

	public void setFixPgtDt(boolean fixPgtDt) {
		this.fixPgtDt = fixPgtDt;
	}
	
	public boolean isFixPgDt(){
		return fixPgtDt;
	}
	
	
	public int getSelectedIndice(){
		if(selectedIndices != null && selectedIndices.length == 1)
			return selectedIndices[0];
		return -1;
	}

	public boolean isCartao(){
		return formaPgtoIndex == FormaPagamento.CARTAO_CREDITO.ordinal();
	}

	public boolean isTransferencia(){
		return this.formaPgtoIndex == FormaPagamento.TRANSFERENCIA.ordinal();
	}
	
	public void setVincular(boolean vincular) {
		this.vincular = vincular;
	}

	public boolean isVincular(){
		return vincular;
	}
	
	
	public void salvar() throws StatizoException{
		int selectedIndex = getSelectedIndice();
		int realIndex = selectedIndex >=0 ? filteredList.get(selectedIndex) : -1;
		int returnIndex = lancamentoService.save(realIndex,dataPgto,dataDiv,
				categoriaIndex,descricao,valor,contaIndex,contaTransferenciaIndex,
				formaPgtoIndex,cartaoIndex,parcelas,pago,parcelado,replicado,vincular);
		
		filter();
		
		try{
			this.selectedIndices = new int[]{ filteredList.indexOf(returnIndex) };
		}catch(IndexOutOfBoundsException e){
			this.selectedIndices = null;
		}

		loadData();
			
	}
	
	public void excluir() throws StatizoException{
		int[] realIndices = getRealIndices(selectedIndices);
		lancamentoService.excluir(realIndices,false);
		filter();
	}

	public void forcarExclusao() throws StatizoException{
		int[] realIndices = getRealIndices(selectedIndices);
		lancamentoService.excluir(realIndices,true);
		filter();
		
	}

	protected int[] getRealIndices(int[] selectedIndices){
		int[] realIndices = new int[selectedIndices.length];
		for(int i = 0; i<selectedIndices.length; i++){
			realIndices[i] = filteredList.get(selectedIndices[i]);
		}
		return realIndices;
	}

	protected int getRealIndice(){
		if(selectedIndices != null && selectedIndices.length == 1)
			return filteredList.get(selectedIndices[0]);
		return -1;
	}
	
	public void loadData(){
		loadData(false);
	}
	
	protected void loadData(boolean preserveFields){

		int selectedIndex = getSelectedIndice();

		if(selectedIndex >=0 ){

			int realIndex = filteredList.get(selectedIndex);
			
			LancamentoData data = lancamentoService.getLancamentoDataAt(realIndex);

			if(!loadingPartial){

				this.dataDiv = data.dataDivida;
				this.dataPgto = data.dataPgto;
				this.descricao = data.descricao;
				this.valor = data.valor;
				this.pago = data.pago;
				this.parcelado = data.parcelado;
				
			}

			if(!loadingPartial || (loadingPartial && partialLoadFlag == LOAD_PARTIAL_CATEGORIA))
				this.categoriaIndex = data.categoria;

			if(!loadingPartial || (loadingPartial && partialLoadFlag == LOAD_PARTIAL_CONTA))
				this.contaIndex = data.conta;

			if(!loadingPartial || (loadingPartial && partialLoadFlag == LOAD_PARTIAL_FORMA_PGTO))
				this.formaPgtoIndex = data.formaPgto;

			if(!loadingPartial || (loadingPartial && partialLoadFlag == LOAD_PARTIAL_CARTAO))
				this.cartaoIndex = data.cartaoCredito;

		}else{

			if(!preserveFields){
				
				if(!fixPgtDt)
					dataPgto = lancamentoService.getDefaultPgtoDate();
				
				dataDiv = new DateData().in(Calendar.getInstance());
				categoriaIndex = -1;
				contaIndex = lancamentoService.getDefaultContaIndex();
				contaTransferenciaIndex = -1;
				formaPgtoIndex = -1;
				cartaoIndex = -1;
				descricao = "";
				valor = "0,00";
				parcelas = "";
				pago = false;
				parcelado = false;
				selectedIndices = null;
				
			}

		}

	}

	public boolean isLancamentosFinalizados(){
		return lancamentoService.isLancamentosFinalizados();
	}
	
	public void liberarLancamentos() throws StatizoException{
		lancamentoService.liberarSaldo();
	}
	
	protected int preserveIndexValue(int index){
		if(index == -1)
			return index;
		return index - 1;
	}
	
	
	public void stopPartialLoading(){
		this.loadingPartial = false;
		this.partialLoadFlag = LOAD_PARTIAL_NONE;
	}

	public String[] getCartoes(){
		String[] all = cartaoService.getNomes();
		String[] cartoes = new String[all.length + 1];
		cartoes[0] = bundle.getString("string.general.choose");
		for(int i = 1; i<all.length + 1; i++){
			cartoes[i] = all[i - 1];
		}
		return cartoes;
	}

	public String[] getCategorias(){
		String[] all = categoriaService.getAllNames();
		String[] categs = new String[all.length + 1];
		categs[0] = bundle.getString("string.general.choose");
		for(int i = 1; i<all.length + 1; i++){
			categs[i] = all[i - 1];
		}
		return categs;
	}

	public String[] getContas(){
		String[] all = contaService.getNomes();
		String[] contas = new String[all.length + 1];
		contas[0] = bundle.getString("string.general.choose");
		for(int i = 1; i<all.length + 1; i++){
			contas[i] = all[i - 1];
		}
		return contas;
	}

	public String[] getFormasPagamento(){
		FormaPagamento[] formasPgto = FormaPagamento.values();
		String [] formas = new String[ formasPgto.length + 1 ];
		formas[0] = bundle.getString("string.general.choose");
		for(int i = 1; i<formas.length; i++){
			formas[i] = bundle.getString(formasPgto[i-1].getNome());
		}
		return formas;
	}

	protected void filter(){
		this.filteredList = lancamentoService.getLancamentos(filter);
	}

	public List<LancamentoTableData> getData(){
		filter();
		List<LancamentoTableData> listData = new ArrayList<LancamentoTableData>();
		for(int i = 0; i<filteredList.size(); i++){
			int realIndex = this.filteredList.get(i);
			LancamentoTableData data = lancamentoService.getAsTableData(realIndex);
			listData.add(data);
		}
		return listData;
	}


	public double getSum(){
		int[] realIndices = getRealIndices(selectedIndices);
		return lancamentoService.getSum(realIndices);
	}

	public Boolean getSituation(){
		int[] realIndices = getRealIndices(selectedIndices);
		return lancamentoService.getSituacoes(realIndices);
	}


	public void marcarComoPago() throws StatizoException{
		int[] realIndices = getRealIndices(selectedIndices);
		lancamentoService.marcarPago(realIndices,true);
	}

	public void marcarComoNaoPago() throws StatizoException{
		int[] realIndices = getRealIndices(selectedIndices);
		lancamentoService.marcarPago(realIndices,false);
	}

	public void marcarComoAgendado() throws StatizoException{
		int[] realIndices = getRealIndices(selectedIndices);
		lancamentoService.marcarAgendado(realIndices,true);
	}

	public void marcarComoNaoAgendado() throws StatizoException{
		int[] realIndices = getRealIndices(selectedIndices);
		lancamentoService.marcarAgendado(realIndices,false);
	}
	
	public boolean isEditing(){
		return selectedIndices != null && selectedIndices.length == 1;
	}
	
	public ResumoData getResumoData(){
		return lancamentoService.getResumoFinanceiroData();
	}
	
	public boolean isSaldoSelecionado(){
		if(lancamentoService.preventIndexOutException(getRealIndice())){
			if(!isEditing()){
				return lancamentoService.isLancamentoSaldo( getRealIndice() );				
			}
		}
		
		return false;
	}
	
	public double getReceitaTotal(int mes, int ano){
		return lancamentoService.getReceitaTotal(mes, ano);
	}
	
	public double getDespesaTotal(int mes, int ano){
		return lancamentoService.getDespesaTotal(mes, ano);
	}

}